#ifndef glm_ext2
#define glm_ext2

namespace glm {
	
    template <typename T>
	T nextPowerOfTwo(T value);

    //! Build a translation matrix.
    template <typename T>
    detail::tmat4x4<T> translationMatrix(
        detail::tvec3<T> const & translation);

    //! Build a translation matrix.
    template <typename T>
    detail::tmat4x4<T> translationMatrix(
        T const x,
        T const y,
        T const z);

    //! Extracts the rotation part of a matrix.
    template <typename T>
    detail::tmat4x4<T> rotationMatrix(
        detail::tmat4x4<T> const & mat);

    //! Build a rotation matrix from axis and angle.
    template <typename T>
    detail::tmat4x4<T> rotationMatrix(
        detail::tvec3<T> const & axis,
        T const angle);

    //! Build a rotation matrix from euler angles.
    template <typename T>
    detail::tmat4x4<T> matrixFromEulerAngles(
        T const pitch,
        T const yaw,
        T const roll);

    //! Build a 3d view matrix.
    template <typename T>
    detail::tmat4x4<T> view3DMatrix(
        detail::tmat4x4<T> const & matrix,
        T aspectRatio = T(1.33333),
        T viewFactor = T(1.0),
        T znear = T(1.0),
        T zfar = T(1000.0));

    //! Build a 3d view matrix.
    template <typename T>
    detail::tmat4x4<T> view3DMatrix(
        detail::tvec3<T> const & position,
        detail::tvec3<T> const & target,
        detail::tvec3<T> const & upVec,
        T aspectRatio = T(1.33333),
        T viewFactor = T(1.0),
        T znear = T(1.0),
        T zfar = T(1000.0));

    //! Build a 2d view matrix.
    template <typename T>
    detail::tmat4x4<T> view2DMatrix(
        T xorigin,
        T yorigin,
        T width,
        T height,
        T znear = T(-1.0),
        T zfar = T(100.0));

	//! Rotates only rotation part of a matrix.
    template <typename T>
    detail::tmat4x4<T> rotateRotationOnly(
        detail::tmat4x4<T> const & m1,
		T angle,
		detail::tvec3<T> const & axis);

} //namespace glm

// implementation
namespace glm
{

	template <typename T>
	inline T nextPowerOfTwo(T value) {
		T powerOfTwo = 1;
		while (powerOfTwo < value)
			powerOfTwo <<= 1;
		return powerOfTwo;
	}

    template <typename T>
    inline detail::tmat4x4<T> matrixFromEulerAngles(
		T const pitch,
		T const yaw,
		T const roll)
    {
		T xc = cos(pitch);
        T xs = sin(pitch);
        T yc = cos(yaw);
        T ys = sin(yaw);
        T zc = cos(roll);
        T zs = sin(roll);
        T xcys = xc * ys;
        T xsys = xs * ys;

        return detail::tmat4x4<T>(
            yc * zc,                -yc * zs,               -ys,        0.0,
            -xsys * zc + xc * zs,   xsys * zs + xc * zc,    -xs * yc,   0.0,
            xcys * zc + xs * zs,    -xcys * zs + xs * zc,   xc * yc,    0.0,
            0.0,                    0.0,                    0.0,        1.0
        );
    }

    template <typename T>
    inline detail::tmat4x4<T> view3DMatrix(
		detail::tvec3<T> const & position,
        detail::tvec3<T> const & target,
        detail::tvec3<T> const & upVec,
        T aspectRatio,
        T viewFactor,
        T znear,
        T zfar)
    {
		return frustum(
            -aspectRatio * viewFactor * 0.5f,
            aspectRatio * viewFactor * 0.5f,
            -viewFactor * 0.5f,
            viewFactor * 0.5f,
            znear,
            zfar
        ) * lookAt(position, target, upVec);
    }

    template <typename T>
    inline detail::tmat4x4<T> view3DMatrix(
		detail::tmat4x4<T> const & matrix,
        T aspectRatio,
        T viewFactor,
        T znear,
        T zfar)
    {
		return frustum(
            -aspectRatio * viewFactor * 0.5f,
            aspectRatio * viewFactor * 0.5f,
            -viewFactor * 0.5f,
            viewFactor * 0.5f,
            znear,
            zfar
        ) * matrix;
    }

    template <typename T>
    inline detail::tmat4x4<T> view2DMatrix(
		T xorigin,
        T yorigin,
        T width,
        T height,
        T znear,
        T zfar)
    {
        return detail::tmat4x4<T>(
            2.0 / ((xorigin + width - 0.5) - (xorigin - 0.5)),		0.0,													0.0,					0.0,
            0.0,													2.0 / ((yorigin - 0.5) - (yorigin + height - 0.5)),		0.0,					0.0,
            0.0,													0.0,													-2.0 / (zfar - znear),	0.0,

            -((xorigin + width - 0.5) + (xorigin - 0.5)) / ((xorigin + width - 0.5) - (xorigin - 0.5)),
            -((yorigin - 0.5) + (yorigin + height - 0.5)) / ((yorigin - 0.5) - (yorigin + height - 0.5)),
            -(zfar + znear) / (zfar - znear),
            1.0
        );
    }

	template <typename T>
    inline detail::tmat4x4<T> rotateRotationOnly(
        detail::tmat4x4<T> const & m1,
		T angle,
		detail::tvec3<T> const & axis)
	{
		detail::tmat4x4<T> m2 = rotate(detail::tmat4x4<T>(), angle, axis);
		detail::tmat3x3<T> r(detail::tmat3x3<T>(m1[0][0], m1[0][1], m1[0][2], m1[1][0], m1[1][1], m1[1][2], m1[2][0], m1[2][1], m1[2][2]) * detail::tmat3x3<T>(m2[0][0], m2[0][1], m2[0][2], m2[1][0], m2[1][1], m2[1][2], m2[2][0], m2[2][1], m2[2][2]));
		return detail::tmat4x4<T>(r[0][0], r[0][1], r[0][2], 0.0, r[1][0], r[1][1], r[1][2], 0.0, r[2][0], r[2][1], r[2][2], 0.0, m1[3][0], m1[3][1], m1[3][2], 1.0);
	}

}//namespace glm

#endif //glm_ext
